Spanner interleave
デフォルトではテーブルのprimary keyを基に自動で分散されるが、以下のようなケースでは親テーブルにinterleaveさせることでクエリのパフォーマンスが向上する
例 users, articles テーブル
table:users
id STRING(36) pk
name STRING(255)
profile STRING(MAX)
table:articles
user_id STRING(36) pk
article_id STRING(36) pk
content STRING(MAX)
article_type INT64
created_at TIMESTAMP
updated_at TIMESTAMP
単一テーブルの複数splitに分かれたデータをまとめてクエリを実行したい
articlesテーブルはuser_id,article_idがpkのため、user_idで絞り込んだ結果は同じsplitにあるとは限らない
usersテーブルにinterleaveさせることで同じsplitにあることを保証できる
code:sh
SELECT * FROM articles WHERE user_id = 'xxxx'
JOIN等で親子テーブルを同じクエリで走査する
このクエリはuser{id: xxxx}があるsplitとarticlesがある全てのsplitを走査する
articlesをusersテーブルにinterleaveさせることで同じsplitにあることを保証できる
code:sh
SELECT users.*, articles.*
FROM users AS u
LEFT OUTER JOIN articles AS a ON a.user_id = u.id
WHERE u.id = 'xxxx'
indexを使用するクエリで、indexのカラムとprimary key以外にテーブルのデータが必要
spannerではindexもtableと同じくキーのカラムを基に分散されるため、テーブルと違うsplitに配置されることがある。indexにはindexのカラムとprimary keyが含まれているが、他のカラムが欲しい場合はSTORING句を指定してカバリングインデックスにできる covering index にするには欲しいカラムが多い場合はinterleaveするのが良い
covering index にする = 更新時にデータをコピーするなのでその分レイテンシが発生する
table:idx_articles_article_type
idx article_type
code:sh
SELECT * FROM articles@{FORCE_INDEX=idx_articles_article_type}
WHERE article_type = 1
interleaveする際、splitのサイズには制限があるため注意する必要がある。splitのサイズ上限を超えてしまうとsplitが分割されてしまうため、パフォーマンスに影響が出る
2020/11時点で4GB
splitのデータサイズを試算する
各カラムが確保するデータサイズを基にどれくらいのデータが必要か試算する
サイズ上限を超えることが見込まれる場合、以下のアプローチ等で対処する必要がある
カラムサイズを小さくできないか検討する
STRING型のMAXサイズは最大値ではなく実際に保存されたデータのサイズが確保されるため、上限を設ける必要がない、サイズの予測がつきにくいといった場合に有効
古いデータは別テーブルに移す、削除する等でレコード数を減らす
interleaveを減らす
ref